package main.java.com.itlin.datastructure.heap;

import java.util.Arrays;

/**
 * 上浮
 * 下潜
 * 堆化
 */

public class MaxHeap {
    int[] array;
    int size;

    public MaxHeap(int capacity){
        this.array = new int[capacity];
    }

    // 构造函数
    public MaxHeap(int[] array) {
        this.array = array;
        this.size = array.length;
        heapify();
    }
    // 建堆
    private void heapify(){
        // 如何找到最后的这个非叶子节点 size / 2 - 1
        for (int i = size/2 - 1; i >= 0; i--) {
            down(i);
        }
    }

    /**
     * 删除堆顶元素
     * @return 堆顶元素
     */
    public int poll() {
        int top = array[0];
        swap(0,size - 1);
        size--;
        down(0);
        return top;
    }

    /**
     * 删除指定索引处元素
     * @param index - 索引
     * @return 被删除元素
     */
    public int poll(int index){
        if (index >= size) throw new IllegalArgumentException("索引超出范围");
        int deleted = array[index];
        swap(index, size - 1);
        size--;
        down(index);
        return deleted;
    }

    /**
     * 获取堆顶元素
     * @return 堆顶元素
     */
    public int peek(){
        if (size == 0) throw new IllegalArgumentException("堆为空");
        return array[0];
    }

    /**
     * 替换堆顶元素
     * @param replaced - 新元素
     */
    public void replace(int replaced){
        if (size == 0) throw new IllegalArgumentException("堆为空");
        array[0] = replaced;
        down(0);
    }

    public boolean offer(int offered){
        if (size == array.length) throw new IllegalArgumentException("堆已满");
        up(offered);
        size++;
        return true;
    }

    // 将 offered 元素上浮： 直至 offered 小于父元素或到堆顶
    private void up(int offered){
        int child = size;
        while (child > 0){
            int parent = (child - 1)/2;
            if (offered > array[parent]){
                array[child] = array[parent];
            }else {
                break;
            }
            child = parent;
        }
        array[child] = offered;
    }

    /**
     * 将 parent索引处的元素下潜： 与两个孩子较大者交换，直至没孩子或孩子没它大
     * @param parent
     */
    private void down(int parent){
        int left = parent * 2 + 1;
        int right = left + 1;
        int max = parent;
        if (left < size && array[left] > array[max]){
            max = left;
        }
        if (right < size && array[right] > array[max]){
            max = right;
        }
        if (max != parent){ // 找到更大的孩子
            swap(max, parent);
            down(max);
        }
    }

    private void swap(int i, int j){
        int t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public static void main(String[] args) {
        int[] array = {2,3,1,7,6,4,5};
        MaxHeap heap = new MaxHeap(array);
        System.out.println(Arrays.toString(heap.array));

        while(heap.size > 1){
            heap.swap(0,heap.size - 1);
            heap.size--;
            heap.down(0);
        }
        System.out.println(Arrays.toString(heap.array));
    }



}

